package thread;

/**
 * 多线程并发的安全问题:
 * 当多个线程并发操作同一临界资源时，由于线程切换时机不确定，导致操作过程的顺序出现了混乱从而导致
 * 操作临界资源出现错误而产生一系列问题。
 * <p>
 * 临界资源:操作该资源的过程同时只能被单一线程进行的资源.
 */
public class SyncDemo {
    public static void main(String[] args) {
        Table t = new Table();
        Thread t1 = new Thread() {
            public void run() {
                while (true) {
                    int boo = t.getBean();
                    Thread.yield();
                    System.out.println(getName() + ":" + boo);
                }
            }
        };
        Thread t2 = new Thread() {
            public void run() {
                while (true) {
                    int boo = t.getBean();
                     /*
                        static void yield()
                        线程提供的这个静态方法作用是让执行该方法的线程
                        主动放弃本次时间片。
                        这里使用它的目的是模拟执行到这里CPU没有时间了，发生
                        线程切换，来看并发安全问题的产生。
                     */
                    Thread.yield();
                    System.out.println(getName() + ":" + boo);
                }
            }
        };
        t1.start();
        t2.start();
    }
}

class Table {
    private int beans = 20;
    /*
        当一个方法使用关键词synchronized修饰后，这个方法称为同步方法，即:多个线程不能同时在方法
        内部执行，只能有先后顺序的一个一个执行该方法。
        将多线程并发操作改为同步排队操作可能有效解决多线程并发安全问题.
     */

    /**
     * synchronized
     */
    public synchronized int getBean() {
        if (beans == 0) {
            throw new RuntimeException("没有倪豆子了...");
        }
        /**
         * 向调度程序提示当前线程愿意放弃其当前对处理器的使用。
         * 调度程序可以随意忽略此提示。
         * <p> Yield 是一种启发式尝试，旨在改善线程之间的相对进程，否则会过度使用 CPU。
         * 它的使用应与详细的分析和基准测试相结合，以确保它确实具有预期的效果。
         * <p> 很少适合使用这种方法。
         * 它对于调试或测试目的可能很有用，它可能有助于重现由于竞争条件引起的错误。
         * 在设计并发控制结构（例如 {@link java.util.concurrent.locks} 包中的结构）时，它也可能很有用。
         */
        Thread.yield();
        return beans--;
    }
}